package hot

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"syscall"
	"time"
)

// GracefulServer 支持优雅重启的服务器
type GracefulServer struct {
	Server     *http.Server
	Listener   net.Listener
	SignalChan chan os.Signal
	isChild    bool
	PidFile    string
}

// NewGracefulServer 创建新的支持优雅重启的服务器
func NewGracefulServer(addr string, handler http.Handler, pidFile string) (*GracefulServer, error) {
	var listener net.Listener
	var err error

	// 检查是否是子进程
	isChild := os.Getenv("RESTART_CHILD") == "true"

	if isChild {
		// 子进程：从父进程继承文件描述符
		log.Println("[INFO] 检测到子进程环境，从父进程继承套接字")
		f := os.NewFile(3, "") // 文件描述符3
		listener, err = net.FileListener(f)
		if err != nil {
			return nil, fmt.Errorf("无法创建listener: %v", err)
		}
		f.Close()
	} else {
		// 父进程：创建新的listener
		log.Printf("[INFO] 创建新的监听器: %s", addr)
		listener, err = net.Listen("tcp", addr)
		if err != nil {
			return nil, fmt.Errorf("无法监听地址 %s: %v", addr, err)
		}
	}

	// 创建HTTP服务器
	server := &http.Server{
		Handler: handler,
	}

	gs := &GracefulServer{
		Server:     server,
		Listener:   listener,
		SignalChan: make(chan os.Signal, 1),
		isChild:    isChild,
		PidFile:    pidFile,
	}

	// 写入PID文件
	if pidFile != "" {
		if err := gs.WritePid(); err != nil {
			log.Printf("[WARN] 写入PID文件失败: %v", err)
		}
	}

	return gs, nil
}

// Start 启动服务器
func (gs *GracefulServer) Start() error {
	// 设置信号处理
	go gs.handleSignals()

	log.Printf("[INFO] 服务器已启动，监听: %v, PID: %d", gs.Listener.Addr(), os.Getpid())

	// 启动服务器
	if err := gs.Server.Serve(gs.Listener); err != http.ErrServerClosed {
		return fmt.Errorf("HTTP服务器错误: %v", err)
	}

	return nil
}

// WritePid 写入PID到文件
func (gs *GracefulServer) WritePid() error {
	if gs.PidFile == "" {
		return nil
	}

	pid := os.Getpid()
	return os.WriteFile(gs.PidFile, []byte(fmt.Sprintf("%d", pid)), 0644)
}

// 处理信号
func (gs *GracefulServer) handleSignals() {
	// 监听SIGUSR2信号用于热重启
	signal.Notify(gs.SignalChan, syscall.SIGUSR2, syscall.SIGINT, syscall.SIGTERM)

	for sig := range gs.SignalChan {
		switch sig {
		case syscall.SIGUSR2:
			// 热重启
			if err := gs.Restart(); err != nil {
				log.Printf("[ERROR] 热重启失败: %v", err)
			}
		case syscall.SIGINT, syscall.SIGTERM:
			// 优雅关闭
			log.Println("[INFO] 收到关闭信号，开始优雅关闭...")
			ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
			defer cancel()
			if err := gs.Server.Shutdown(ctx); err != nil {
				log.Printf("[ERROR] 服务器关闭错误: %v", err)
			}
			os.Exit(0)
		}
	}
}

// Restart 执行热重启
func (gs *GracefulServer) Restart() error {
	log.Println("[INFO] 收到热重启信号，准备重启...")

	// 获取当前可执行文件路径
	execPath, err := os.Executable()
	if err != nil {
		return fmt.Errorf("无法获取可执行文件路径: %v", err)
	}

	// 准备文件描述符
	listenerFile, err := gs.Listener.(*net.TCPListener).File()
	if err != nil {
		return fmt.Errorf("无法获取listener的文件描述符: %v", err)
	}

	// 准备子进程环境
	env := append(os.Environ(), "RESTART_CHILD=true")

	// 启动子进程
	cmd := exec.Command(execPath, os.Args[1:]...)
	cmd.Env = env
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	// 传递文件描述符
	cmd.ExtraFiles = []*os.File{listenerFile}

	if err := cmd.Start(); err != nil {
		return fmt.Errorf("无法启动子进程: %v", err)
	}

	log.Printf("[INFO] 子进程已启动，PID: %d", cmd.Process.Pid)

	// 等待一些时间后关闭当前进程
	go func() {
		time.Sleep(3 * time.Second) // 给子进程一些时间来启动
		log.Println("[INFO] 旧进程即将退出")
		gs.Server.Shutdown(context.Background())
		os.Exit(0)
	}()

	return nil
}
